# import logging - replaced with loguru
import ipaddress
import os
from pathlib import Path
from importlib import resources as importlib_resources

from flask import (
    Flask,
    jsonify,
    make_response,
    request,
    send_from_directory,
)
from flask_wtf.csrf import CSRFProtect
from werkzeug.middleware.proxy_fix import ProxyFix
from loguru import logger
from local_deep_research.settings.logger import log_settings

from ..utilities.log_utils import InterceptHandler
from ..security import SecurityHeaders
from .utils.rate_limiter import limiter
from ..security.file_upload_validator import FileUploadValidator

# Removed DB_PATH import - using per-user databases now
from .services.socket_service import SocketIOService


def _is_private_ip(ip_str: str) -> bool:
    """Check if IP is a private/local network address (RFC 1918 + localhost).

    This allows LAN access over HTTP without requiring HTTPS, matching the
    behavior of other self-hosted applications like Jellyfin and Home Assistant.

    Private ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, plus localhost.
    """
    try:
        ip = ipaddress.ip_address(ip_str)
        return ip.is_private or ip.is_loopback
    except ValueError:
        return False


def create_app():
    """
    Create and configure the Flask application.

    Returns:
        tuple: (app, socketio) - The configured Flask app and SocketIO instance
    """
    # Set Werkzeug logger to WARNING level to suppress Socket.IO polling logs
    import logging

    logging.getLogger("werkzeug").setLevel(logging.WARNING)
    logging.getLogger("werkzeug").addHandler(InterceptHandler())

    logger.info("Initializing Local Deep Research application...")

    try:
        # Get directories based on package installation
        PACKAGE_DIR = importlib_resources.files("local_deep_research") / "web"
        with importlib_resources.as_file(PACKAGE_DIR) as package_dir:
            STATIC_DIR = (package_dir / "static").as_posix()
            TEMPLATE_DIR = (package_dir / "templates").as_posix()

        # Initialize Flask app with package directories
        # Set static_folder to None to disable Flask's built-in static handling
        # We'll use our custom static route instead to handle dist folder
        app = Flask(__name__, static_folder=None, template_folder=TEMPLATE_DIR)
        # Store static dir for custom handling
        app.config["STATIC_DIR"] = STATIC_DIR
        logger.debug(f"Using package static path: {STATIC_DIR}")
        logger.debug(f"Using package template path: {TEMPLATE_DIR}")
    except Exception:
        # Fallback for development
        logger.exception("Package directories not found, using fallback paths")
        # Set static_folder to None to disable Flask's built-in static handling
        app = Flask(
            __name__,
            static_folder=None,
            template_folder=str(Path("templates").resolve()),
        )
        # Store static dir for custom handling
        app.config["STATIC_DIR"] = str(Path("static").resolve())

    # Add proxy support for deployments behind load balancers/reverse proxies
    # This ensures X-Forwarded-For and X-Forwarded-Proto headers are properly handled
    # Important for rate limiting and security (gets real client IP, not proxy IP)
    app.wsgi_app = ProxyFix(
        app.wsgi_app,
        x_for=1,  # Trust 1 proxy for X-Forwarded-For
        x_proto=1,  # Trust 1 proxy for X-Forwarded-Proto (http/https)
        x_host=0,  # Don't trust X-Forwarded-Host (security)
        x_port=0,  # Don't trust X-Forwarded-Port (security)
        x_prefix=0,  # Don't trust X-Forwarded-Prefix (security)
    )

    # WSGI middleware for dynamic cookie security
    # This wraps AFTER ProxyFix so we have access to the real client IP
    # Must be WSGI level because Flask session cookies are set after after_request handlers
    class SecureCookieMiddleware:
        """WSGI middleware to add Secure flag to cookies based on request context.

        Security model:
        - Localhost HTTP (127.0.0.1, ::1): Skip Secure flag (local traffic is safe)
        - Proxied requests (X-Forwarded-For present): Add Secure flag (production)
        - Non-localhost HTTP: Add Secure flag (will fail, by design - use HTTPS)
        - TESTING mode: Never add Secure flag (for CI/development)

        This prevents X-Forwarded-For spoofing attacks by checking for the header's
        presence rather than its value - if the header exists, we're behind a proxy.
        """

        def __init__(self, wsgi_app, flask_app):
            self.wsgi_app = wsgi_app
            self.flask_app = flask_app

        def __call__(self, environ, start_response):
            # Check if we should add Secure flag
            should_add_secure = self._should_add_secure_flag(environ)

            def custom_start_response(status, headers, exc_info=None):
                if should_add_secure:
                    # Modify Set-Cookie headers to add Secure flag
                    new_headers = []
                    for name, value in headers:
                        if name.lower() == "set-cookie":
                            if (
                                "; Secure" not in value
                                and "; secure" not in value
                            ):
                                value = value + "; Secure"
                        new_headers.append((name, value))
                    headers = new_headers
                return start_response(status, headers, exc_info)

            return self.wsgi_app(environ, custom_start_response)

        def _should_add_secure_flag(self, environ):
            """Determine if Secure flag should be added based on request context.

            Security model:
            - Check the ACTUAL connection IP (REMOTE_ADDR), not X-Forwarded-For header
            - SecureCookieMiddleware is outer wrapper, so we see original REMOTE_ADDR
            - If connection comes from private IP (client or proxy), allow HTTP
            - If connection comes from public IP, require HTTPS

            This is safe because:
            - We never trust X-Forwarded-For header values (can be spoofed)
            - We only check the actual TCP connection source IP
            - Spoofing X-Forwarded-For from public IP doesn't bypass this check
            - Local proxies (nginx on localhost/LAN) have private REMOTE_ADDR
            """
            # Skip if in explicit testing mode
            if self.flask_app.config.get("LDR_TESTING_MODE"):
                return False

            # Check actual connection source IP (before ProxyFix modifies it)
            # This is either:
            # - Direct client IP (if no proxy)
            # - Proxy server IP (if behind proxy)
            # Local proxies (nginx on localhost, Traefik on LAN) have private IPs
            remote_addr = environ.get("REMOTE_ADDR", "")
            is_private = _is_private_ip(remote_addr)

            # Check if HTTPS
            is_https = environ.get("wsgi.url_scheme") == "https"

            # Add Secure flag if:
            # - Using HTTPS (always secure over HTTPS)
            # - OR connection is from public IP (require HTTPS for public access)
            return is_https or not is_private

    # Wrap the app with our cookie security middleware
    app.wsgi_app = SecureCookieMiddleware(app.wsgi_app, app)

    # App configuration
    # Generate or load a unique SECRET_KEY per installation
    import secrets
    from ..config.paths import get_data_directory

    secret_key_file = Path(get_data_directory()) / ".secret_key"
    if secret_key_file.exists():
        try:
            with open(secret_key_file, "r") as f:
                app.config["SECRET_KEY"] = f.read().strip()
        except Exception as e:
            logger.warning(f"Could not read secret key file: {e}")
            app.config["SECRET_KEY"] = secrets.token_hex(32)
    else:
        # Generate a new key on first run
        new_key = secrets.token_hex(32)
        try:
            secret_key_file.parent.mkdir(parents=True, exist_ok=True)
            with open(secret_key_file, "w") as f:
                f.write(new_key)
            secret_key_file.chmod(0o600)  # Secure file permissions
            app.config["SECRET_KEY"] = new_key
            logger.info("Generated new SECRET_KEY for this installation")
        except Exception as e:
            logger.warning(f"Could not save secret key file: {e}")
            app.config["SECRET_KEY"] = new_key
    # Session cookie security settings
    # SECURE flag is added dynamically based on request context (see after_request below)
    # This allows localhost HTTP to work for development while keeping production secure
    #
    # Check if explicitly in testing mode (for backwards compatibility)
    is_testing = (
        os.getenv("CI")
        or os.getenv("TESTING")
        or os.getenv("PYTEST_CURRENT_TEST")
        or app.debug
    )
    # Set to False - we add Secure flag dynamically in after_request handler
    # Exception: if TESTING mode is active, we never add Secure flag
    app.config["SESSION_COOKIE_SECURE"] = False
    app.config["LDR_TESTING_MODE"] = bool(is_testing)  # Store for after_request
    app.config["SESSION_COOKIE_HTTPONLY"] = (
        True  # Prevent JavaScript access (XSS mitigation)
    )
    app.config["SESSION_COOKIE_SAMESITE"] = "Lax"  # CSRF protection
    app.config["PERMANENT_SESSION_LIFETIME"] = 7200  # 2 hours in seconds
    # PREFERRED_URL_SCHEME affects URL generation (url_for), not request.is_secure
    app.config["PREFERRED_URL_SCHEME"] = "https"

    # File upload security limits - calculated from FileUploadValidator constants
    app.config["MAX_CONTENT_LENGTH"] = (
        FileUploadValidator.MAX_FILES_PER_REQUEST
        * FileUploadValidator.MAX_FILE_SIZE
    )

    # Initialize CSRF protection
    # Explicitly enable CSRF protection (don't rely on implicit Flask-WTF behavior)
    app.config["WTF_CSRF_ENABLED"] = True
    CSRFProtect(app)
    # Exempt Socket.IO from CSRF protection
    # Note: Flask-SocketIO handles CSRF internally, so we don't need to exempt specific views

    # Initialize security headers middleware
    SecurityHeaders(app)

    # Initialize rate limiting for security (brute force protection)
    # Uses imported limiter from utils.rate_limiter module
    # Rate limiting is disabled in CI via enabled callable in rate_limiter.py
    # Also set app config to ensure Flask-Limiter respects our settings
    from ..settings.env_registry import is_rate_limiting_enabled

    app.config["RATELIMIT_ENABLED"] = is_rate_limiting_enabled()
    limiter.init_app(app)

    # Custom error handler for rate limit exceeded (429)
    @app.errorhandler(429)
    def ratelimit_handler(e):
        # Import here to avoid circular imports
        from .utils.rate_limiter import get_client_ip

        # Audit logging for security monitoring
        # Use get_client_ip() to get the real IP behind proxies
        logger.warning(
            f"Rate limit exceeded: endpoint={request.endpoint} "
            f"ip={get_client_ip()} "
            f"user_agent={request.headers.get('User-Agent', 'unknown')}"
        )
        return jsonify(
            error="Too many requests",
            message="Too many attempts. Please try again later.",
        ), 429

    # Note: Dynamic cookie security is handled by SecureCookieMiddleware (WSGI level)
    # This is necessary because Flask's session cookies are set AFTER after_request handlers
    # The middleware wrapping happens below near ProxyFix

    # Disable CSRF for API routes
    @app.before_request
    def disable_csrf_for_api():
        if (
            request.path.startswith("/api/v1/")
            or request.path.startswith("/research/api/")
            or request.path.startswith("/benchmark/api/")
        ):
            # Mark this request as exempt from CSRF
            request.environ["csrf_exempt"] = True

    # Database configuration - Using per-user databases now
    # No shared database configuration needed
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    app.config["SQLALCHEMY_ECHO"] = False

    # Per-user databases are created automatically via encrypted_db.py

    # Log data location and security information
    from ..config.paths import get_data_directory
    from ..database.encrypted_db import db_manager

    data_dir = get_data_directory()
    logger.info("=" * 60)
    logger.info("DATA STORAGE INFORMATION")
    logger.info("=" * 60)
    logger.info(f"Data directory: {data_dir}")
    logger.info(
        "Databases: Per-user encrypted databases in encrypted_databases/"
    )

    # Check if using custom location
    from local_deep_research.settings.manager import SettingsManager

    settings_manager = SettingsManager()
    custom_data_dir = settings_manager.get_setting("bootstrap.data_dir")
    if custom_data_dir:
        logger.info(
            f"Using custom data location via LDR_DATA_DIR: {custom_data_dir}"
        )
    else:
        logger.info("Using default platform-specific data location")

    # Display security status based on actual SQLCipher availability
    if db_manager.has_encryption:
        logger.info(
            "SECURITY: Databases are encrypted with SQLCipher. Ensure appropriate file system permissions are set on the data directory."
        )
    else:
        logger.warning(
            "SECURITY NOTICE: SQLCipher is not available - databases are NOT encrypted. "
            "Install SQLCipher for database encryption. Ensure appropriate file system permissions are set on the data directory."
        )

    logger.info(
        "TIP: You can change the data location by setting the LDR_DATA_DIR environment variable."
    )
    logger.info("=" * 60)

    # Initialize Vite helper for asset management
    from .utils.vite_helper import vite

    vite.init_app(app)

    # Register socket service
    socket_service = SocketIOService(app=app)

    # Initialize news subscription scheduler
    try:
        # Always initialize news for now - per-user enabling will be handled in routes
        if True:
            # News tables are now created per-user in their encrypted databases
            logger.info(
                "News tables will be created in per-user encrypted databases"
            )

            # Check if scheduler is enabled BEFORE importing/initializing
            # Use env registry which handles both env vars and settings
            from ..settings.env_registry import get_env_setting

            scheduler_enabled = get_env_setting("news.scheduler.enabled", True)
            logger.info(f"News scheduler enabled: {scheduler_enabled}")

            if scheduler_enabled:
                # Only import and initialize if enabled
                from ..news.subscription_manager.scheduler import (
                    get_news_scheduler,
                )
                from ..settings.manager import SettingsManager

                # Get system settings for scheduler configuration (if not already loaded)
                if "settings_manager" not in locals():
                    settings_manager = SettingsManager()

                # Get scheduler instance and initialize with settings
                scheduler = get_news_scheduler()
                scheduler.initialize_with_settings(settings_manager)
                scheduler.start()
                app.news_scheduler = scheduler
                logger.info(
                    "News scheduler started with activity-based tracking"
                )
            else:
                # Don't initialize scheduler if disabled
                app.news_scheduler = None
                logger.info("News scheduler disabled - not initializing")
        else:
            logger.info(
                "News module disabled - subscription scheduler not started"
            )
            app.news_scheduler = None
    except Exception:
        logger.exception("Failed to initialize news scheduler")
        app.news_scheduler = None

    # Apply middleware
    logger.info("Applying middleware...")
    apply_middleware(app)
    logger.info("Middleware applied successfully")

    # Register blueprints
    logger.info("Registering blueprints...")
    register_blueprints(app)
    logger.info("Blueprints registered successfully")

    # Register error handlers
    logger.info("Registering error handlers...")
    register_error_handlers(app)
    logger.info("Error handlers registered successfully")

    # Start the queue processor v2 (uses encrypted databases)
    # Always start the processor - it will handle per-user queue modes
    logger.info("Starting queue processor v2...")
    from .queue.processor_v2 import queue_processor

    queue_processor.start()
    logger.info("Started research queue processor v2")

    logger.info("App factory completed successfully")

    return app, socket_service


def apply_middleware(app):
    """Apply middleware to the Flask app."""

    # Import auth decorators and middleware
    logger.info("Importing cleanup_middleware...")
    from .auth.cleanup_middleware import cleanup_completed_research

    logger.info("Importing database_middleware...")
    from .auth.database_middleware import ensure_user_database

    logger.info("Importing decorators...")
    from .auth.decorators import inject_current_user

    logger.info("Importing queue_middleware...")
    from .auth.queue_middleware import process_pending_queue_operations

    logger.info("Importing queue_middleware_v2...")
    from .auth.queue_middleware_v2 import notify_queue_processor

    logger.info("Importing session_cleanup...")
    from .auth.session_cleanup import cleanup_stale_sessions

    logger.info("All middleware imports completed")

    # Register authentication middleware
    # First clean up stale sessions
    app.before_request(cleanup_stale_sessions)
    # Then ensure database is open for authenticated users
    app.before_request(ensure_user_database)
    # Then inject current user into g
    app.before_request(inject_current_user)
    # Clean up completed research records
    app.before_request(cleanup_completed_research)
    # Process any pending queue operations for this user (direct mode)
    app.before_request(process_pending_queue_operations)
    # Notify queue processor of user activity (queue mode)
    app.before_request(notify_queue_processor)

    logger.info("All middleware registered")

    # Flush any queued logs from background threads
    logger.info("Importing log_utils...")
    from ..utilities.log_utils import flush_log_queue

    app.before_request(flush_log_queue)
    logger.info("Log flushing middleware registered")

    # Clean up database sessions after each request
    @app.teardown_appcontext
    def cleanup_db_session(exception=None):
        """Clean up database session after each request to avoid cross-thread issues."""
        from flask import g

        if hasattr(g, "db_session"):
            try:
                if g.db_session:
                    g.db_session.close()
            except Exception:
                pass  # Ignore errors during cleanup
            finally:
                g.db_session = None

    # Add a middleware layer to handle abrupt disconnections
    @app.before_request
    def handle_websocket_requests():
        if request.path.startswith("/socket.io"):
            try:
                if not request.environ.get("werkzeug.socket"):
                    return
            except Exception:
                logger.exception("WebSocket preprocessing error")
                # Return empty response to prevent further processing
                return "", 200

    # Note: CORS headers for API routes are now handled by SecurityHeaders middleware
    # (see src/local_deep_research/security/security_headers.py)


def register_blueprints(app):
    """Register blueprints with the Flask app."""

    # Import blueprints
    logger.info("Importing blueprints...")

    # Import benchmark blueprint
    from ..benchmarks.web_api.benchmark_routes import benchmark_bp

    logger.info("Importing API blueprint...")
    from .api import api_blueprint  # Import the API blueprint

    logger.info("Importing auth blueprint...")
    from .auth import auth_bp  # Import the auth blueprint

    logger.info("Importing API routes blueprint...")
    from .routes.api_routes import api_bp  # Import the API blueprint

    logger.info("Importing context overflow API...")
    from .routes.context_overflow_api import (
        context_overflow_bp,
    )  # Import context overflow API

    logger.info("Importing history routes...")
    from .routes.history_routes import history_bp

    logger.info("Importing metrics routes...")
    from .routes.metrics_routes import metrics_bp

    logger.info("Importing research routes...")
    from .routes.research_routes import research_bp

    logger.info("Importing settings routes...")
    from .routes.settings_routes import settings_bp

    logger.info("All core blueprints imported successfully")

    # Add root route
    @app.route("/")
    def index():
        """Root route - redirect to login if not authenticated"""
        from flask import redirect, session, url_for

        from ..database.session_context import get_user_db_session
        from ..utilities.db_utils import get_settings_manager
        from .utils.templates import render_template_with_defaults

        # Check if user is authenticated
        if "username" not in session:
            return redirect(url_for("auth.login"))

        # Load current settings from database using proper session context
        username = session.get("username")
        settings = {}
        with get_user_db_session(username) as db_session:
            if db_session:
                settings_manager = get_settings_manager(db_session, username)
                settings = {
                    "llm_provider": settings_manager.get_setting(
                        "llm.provider", "ollama"
                    ),
                    "llm_model": settings_manager.get_setting("llm.model", ""),
                    "llm_openai_endpoint_url": settings_manager.get_setting(
                        "llm.openai_endpoint.url", ""
                    ),
                    "llm_ollama_url": settings_manager.get_setting(
                        "llm.ollama.url"
                    ),
                    "llm_lmstudio_url": settings_manager.get_setting(
                        "llm.lmstudio.url"
                    ),
                    "llm_local_context_window_size": settings_manager.get_setting(
                        "llm.local_context_window_size"
                    ),
                    "search_tool": settings_manager.get_setting(
                        "search.tool", ""
                    ),
                    "search_iterations": settings_manager.get_setting(
                        "search.iterations", 2
                    ),
                    "search_questions_per_iteration": settings_manager.get_setting(
                        "search.questions_per_iteration", 3
                    ),
                    "search_strategy": settings_manager.get_setting(
                        "search.search_strategy", "source-based"
                    ),
                }

        # Debug logging
        log_settings(settings, "Research page settings loaded")

        return render_template_with_defaults(
            "pages/research.html", settings=settings
        )

    # Register auth blueprint FIRST (so login page is accessible)
    app.register_blueprint(auth_bp)  # Already has url_prefix="/auth"

    # Register other blueprints
    app.register_blueprint(research_bp)
    app.register_blueprint(history_bp)  # Already has url_prefix="/history"
    app.register_blueprint(metrics_bp)
    app.register_blueprint(settings_bp)  # Already has url_prefix="/settings"
    app.register_blueprint(
        api_bp, url_prefix="/research/api"
    )  # Register API blueprint with prefix
    app.register_blueprint(benchmark_bp)  # Register benchmark blueprint
    app.register_blueprint(
        context_overflow_bp, url_prefix="/metrics"
    )  # Register context overflow API

    # Register news API routes
    from .routes import news_routes

    app.register_blueprint(news_routes.bp)
    logger.info("News API routes registered successfully")

    # Register follow-up research routes
    from ..followup_research.routes import followup_bp

    app.register_blueprint(followup_bp)
    logger.info("Follow-up research routes registered successfully")

    # Register news page blueprint
    from ..news.web import create_news_blueprint

    news_bp = create_news_blueprint()
    app.register_blueprint(news_bp, url_prefix="/news")
    logger.info("News page routes registered successfully")

    # Register API v1 blueprint
    app.register_blueprint(api_blueprint)  # Already has url_prefix='/api/v1'

    # Register Research Library blueprint
    from ..research_library import library_bp, rag_bp, delete_bp

    app.register_blueprint(library_bp)  # Already has url_prefix='/library'
    logger.info("Research Library routes registered successfully")

    # Register RAG Management blueprint
    app.register_blueprint(rag_bp)  # Already has url_prefix='/library'
    logger.info("RAG Management routes registered successfully")

    # Register Deletion Management blueprint
    app.register_blueprint(delete_bp)  # Already has url_prefix='/library/api'
    logger.info("Deletion Management routes registered successfully")

    # Register Document Scheduler blueprint
    from ..research_scheduler.routes import scheduler_bp

    app.register_blueprint(scheduler_bp)
    logger.info("Document Scheduler routes registered successfully")

    # After registration, update CSRF exemptions
    if hasattr(app, "extensions") and "csrf" in app.extensions:
        csrf = app.extensions["csrf"]
        # Exempt the API blueprint routes by actual endpoints
        csrf.exempt("api_v1")
        csrf.exempt("api")
        for rule in app.url_map.iter_rules():
            if rule.endpoint and (
                rule.endpoint.startswith("api_v1.")
                or rule.endpoint.startswith("api.")
            ):
                csrf.exempt(rule.endpoint)

    # Add favicon route
    # Exempt favicon from rate limiting
    @app.route("/favicon.ico")
    @limiter.exempt
    def favicon():
        static_dir = app.config.get("STATIC_DIR", "static")
        return send_from_directory(
            static_dir, "favicon.ico", mimetype="image/x-icon"
        )

    # Add static route at the app level for compatibility
    # Exempt static files from rate limiting
    @app.route("/static/<path:path>")
    @limiter.exempt
    def app_serve_static(path):
        from ..security.path_validator import PathValidator

        static_dir = Path(app.config.get("STATIC_DIR", "static"))

        # First try to serve from dist directory (for built assets)
        dist_dir = static_dir / "dist"
        try:
            # Use PathValidator to safely validate the path
            validated_path = PathValidator.validate_safe_path(
                path,
                dist_dir,
                allow_absolute=False,
                required_extensions=None,  # Allow any file type for static assets
            )

            if validated_path and validated_path.exists():
                return send_from_directory(str(dist_dir), path)
        except (ValueError, Exception):
            # Path validation failed, try regular static folder
            pass

        # Fall back to regular static folder
        try:
            validated_path = PathValidator.validate_safe_path(
                path, static_dir, allow_absolute=False, required_extensions=None
            )

            if validated_path and validated_path.exists():
                return send_from_directory(str(static_dir), path)
        except (ValueError, Exception):
            # Path validation failed
            pass

        return make_response(jsonify({"error": "Not found"}), 404)


def register_error_handlers(app):
    """Register error handlers with the Flask app."""

    @app.errorhandler(404)
    def not_found(error):
        return make_response(jsonify({"error": "Not found"}), 404)

    @app.errorhandler(500)
    def server_error(error):
        return make_response(jsonify({"error": "Server error"}), 500)

    # Handle CSRF validation errors with helpful message
    try:
        from flask_wtf.csrf import CSRFError

        @app.errorhandler(CSRFError)
        def handle_csrf_error(error):
            """Handle CSRF errors with helpful debugging info."""
            # Check if this might be a Secure cookie issue over HTTP
            is_http = not request.is_secure
            is_private = _is_private_ip(request.remote_addr or "")
            is_proxied = request.headers.get("X-Forwarded-For") is not None

            error_msg = str(error.description)

            # Provide detailed help for HTTP + public IP or proxied scenario
            if is_http and (not is_private or is_proxied):
                logger.warning(
                    f"CSRF validation failed - likely due to Secure cookie over HTTP. "
                    f"remote_addr={request.remote_addr}, proxied={is_proxied}, "
                    f"host={request.host}"
                )
                error_msg = (
                    "Session cookie error: You're accessing over HTTP from a "
                    "public IP address or through a proxy. "
                    "This is blocked for security reasons.\n\n"
                    "Solutions:\n"
                    "1. Use HTTPS with a reverse proxy (recommended for production)\n"
                    "2. Access from your local network (LAN IPs like 192.168.x.x work over HTTP)\n"
                    "3. Access directly from localhost (http://127.0.0.1:5000)\n"
                    "4. Use SSH tunnel: ssh -L 5000:localhost:5000 user@server, "
                    "then access http://localhost:5000\n\n"
                    "Note: LAN access (192.168.x.x, 10.x.x.x, 172.16-31.x.x) works over HTTP. "
                    "Only public internet access requires HTTPS."
                )

            return make_response(jsonify({"error": error_msg}), 400)
    except ImportError:
        pass

    # Handle News API exceptions globally
    try:
        from ..news.exceptions import NewsAPIException

        @app.errorhandler(NewsAPIException)
        def handle_news_api_exception(error):
            """Handle NewsAPIException and convert to JSON response."""
            from loguru import logger

            logger.error(
                f"News API error: {error.message} (code: {error.error_code})"
            )
            return jsonify(error.to_dict()), error.status_code
    except ImportError:
        # News module not available
        pass


def create_database(app):
    """
    DEPRECATED: Database creation is now handled per-user via encrypted_db.py
    This function is kept for compatibility but does nothing.
    """
    pass
